package com.snakeway.pdfviewer;

import android.graphics.RectF;
import android.os.AsyncTask;
import android.util.Log;

import com.snakeway.pdflibrary.PdfiumCore;
import com.snakeway.pdfviewer.listener.OnSearchTagSectionsListener;
import com.snakeway.pdfviewer.model.TagSectionInfo;
import com.snakeway.pdfviewer.util.UnicodeUtil;

import java.util.ArrayList;
import java.util.List;


class SearchTagSectionsAsyncTask extends AsyncTask<Void, Void, List<TagSectionInfo>> {

    private PdfiumCore pdfiumCore;
    private String tag;
    private List<Integer> pageIndexs;
    private List<Long> textPagesPtrs;
    private int appendBoundaryCount;
    private OnSearchTagSectionsListener onSearchTagSectionsListener;


    SearchTagSectionsAsyncTask(PdfiumCore pdfiumCore, String tag, List<Integer> pageIndexs, List<Long> textPagesPtrs, int appendBoundaryCount, OnSearchTagSectionsListener onSearchTagSectionsListener) {
        this.pdfiumCore = pdfiumCore;
        this.tag = tag;
        this.pageIndexs = pageIndexs;
        this.textPagesPtrs = textPagesPtrs;
        this.appendBoundaryCount = appendBoundaryCount;
        this.onSearchTagSectionsListener = onSearchTagSectionsListener;
    }

    @Override
    protected List<TagSectionInfo> doInBackground(Void... params) {
        if (pdfiumCore == null || tag == null) {
            return null;
        }
        if (pageIndexs == null || textPagesPtrs == null || (pageIndexs.size() != textPagesPtrs.size())) {
            return null;
        }
        List<TagSectionInfo> tagSections = new ArrayList<>();
        for (int i = 0; i < pageIndexs.size(); i++) {
            int pageIndex = pageIndexs.get(i);
            long textPagesPtr = textPagesPtrs.get(i);
            int count = pdfiumCore.getPageTextCount(textPagesPtr);
            if (count > 0) {
                tagSections.addAll(searchTagSectionInfosWithTag(textPagesPtr, pageIndex, count, tag));
            }
        }
        return tagSections;
    }

    private List<TagSectionInfo> searchTagSectionInfosWithTag(long textPagesPtr, int page, int count, String tag) {
        List<TagSectionInfo> tagSectionInfos = new ArrayList<>();
        int begin = 0;
        while (true) {
            if (begin > count) {
                break;
            }
            TagSectionInfo tagSectionInfo = searchTagSection(textPagesPtr, page, begin, count, tag);
            if (tagSectionInfo != null) {
                begin = tagSectionInfo.getEnd() + 1;
                tagSectionInfos.add(tagSectionInfo);
            } else {
                break;
            }
        }
        return tagSectionInfos;
    }

    private TagSectionInfo searchTagSection(long textPagesPtr, int page, int begin, int count, String tag) {
        if (tag == null || tag.length() == 0 || begin >= count) {
            return null;
        }
        boolean findSuccess = false;
        int start = 0;
        int end = 0;
        String boundaryBegin = null;
        String target = null;
        String boundaryEnd = null;
        for (int i = begin; i < count; i++) {
            List<Object> resultObjects = doSearchTagSection(textPagesPtr, tag, i, count);
            if (resultObjects != null && resultObjects.size() == 4) {
                int[] res = (int[]) resultObjects.get(0);
                boundaryBegin = (String) resultObjects.get(1);
                target = (String) resultObjects.get(2);
                boundaryEnd = (String) resultObjects.get(3);
                findSuccess = true;
                start = res[0];
                end = res[1];
                break;
            }
        }
        if (!findSuccess) {
            return null;
        }
        List<RectF> areaRects = new ArrayList<>();
        for (int i = start; i <= end; i++) {
            areaRects.add(pdfiumCore.getTextRect(textPagesPtr, i));
        }
        TagSectionInfo tagSectionInfo = new TagSectionInfo(start, end, areaRects, page);
        tagSectionInfo.setBoundaryBegin(boundaryBegin);
        tagSectionInfo.setTarget(target);
        tagSectionInfo.setBoundaryEnd(boundaryEnd);
        return tagSectionInfo;
    }

    private List<Object> doSearchTagSection(long textPagesPtr, String tag, int start, int end) {
        List<Object> resultObjects = new ArrayList<>();
        int[] result = null;
        int nextCheckIndex = 0;
        StringBuilder append = new StringBuilder();
        StringBuilder appendBoundaryBegin = new StringBuilder();
        StringBuilder appendBoundaryEnd = new StringBuilder();
        int findStart = 0;
        int findCount = 0;
        for (int i = start; i < end; i++) {
            int unicode = pdfiumCore.searchTextUnicode(textPagesPtr, i);
            if (unicode <= 0) {
                continue;
            }
            String targetChar = String.valueOf(tag.charAt(nextCheckIndex));
            String unicodeString = UnicodeUtil.convertUnicode(unicode);
            String code = UnicodeUtil.unicodeToString(unicodeString);
            if (!code.equals(targetChar)) {
                if (!append.toString().equals("") && (unicodeString.equals("\\u000d") || unicodeString.equals("\\u000a"))) {
                    findCount++;
                    continue;
                }
                break;
            }
            if (append.toString().equals("")) {
                findStart = i;
            }
            append.append(code);
            if (append.toString().equals(tag)) {
                result = new int[2];
                result[0] = findStart;
                result[1] = findStart + findCount;
                break;
            }
            findCount++;
            nextCheckIndex++;
        }
        if (result == null) {
            return null;
        }
        for (int i = result[0] - 1; i > 0; i--) {
            int unicode = pdfiumCore.searchTextUnicode(textPagesPtr, i);
            String unicodeString = UnicodeUtil.convertUnicode(unicode);
            String code = UnicodeUtil.unicodeToString(unicodeString);
            if (isIgnoreCode(unicodeString)) {
                continue;
            }
            Log.e("append begin:", code + "," + unicodeString);
            appendBoundaryBegin.append(code);
            if (appendBoundaryBegin.length() >= appendBoundaryCount) {
                appendBoundaryBegin.reverse();
                break;
            }
        }
        for (int i = result[1] + 1; i < end; i++) {
            int unicode = pdfiumCore.searchTextUnicode(textPagesPtr, i);
            String unicodeString = UnicodeUtil.convertUnicode(unicode);
            String code = UnicodeUtil.unicodeToString(unicodeString);
            if (isIgnoreCode(unicodeString)) {
                continue;
            }
            Log.e("append end:", code + "," + unicodeString);
            appendBoundaryEnd.append(code);
            if (appendBoundaryEnd.length() >= appendBoundaryCount) {
                break;
            }
        }
        resultObjects.add(result);
        resultObjects.add(appendBoundaryBegin.toString());
        resultObjects.add(append.toString());
        resultObjects.add(appendBoundaryEnd.toString());
        return resultObjects;
    }

    private boolean isIgnoreCode(String unicodeString) {
        return unicodeString.equals("\\u000d") || unicodeString.equals("\\u000a") || unicodeString.equals("\\u0020");
    }

    @Override
    protected void onPostExecute(List<TagSectionInfo> tagSectionInfos) {
        if (onSearchTagSectionsListener != null) {
            onSearchTagSectionsListener.onResult(tagSectionInfos);
        }
    }

    @Override
    protected void onCancelled() {
        if (onSearchTagSectionsListener != null) {
            onSearchTagSectionsListener.onCancel();
        }
    }

}
